#include "SignJson.h"
#include <iostream>
#include <fstream>
#include <streambuf>
#include "libjson.h"
#include "control/TermControl.h"


namespace xpm {	
	
	void SignJson::Init() {
		// optionally you can implement your DOMLSSerializerFilter (e.g. MyDOMLSSerializerFilter)		
	}

	SignJson::~SignJson() {
		
	}

	wstring SignJson::Load(XpmTermDoc& doc) {
		return ParseWithJson(m_filename.c_str(), doc);
	}

	bool SignJson::Save(XpmTermDoc& doc, wstring& syntax) {
		return SaveAs(doc, m_filename.c_str(), syntax);
	}

	bool SignJson::SaveAs(XpmTermDoc& doc, const char* filename, wstring& syntax) {
		// get syntax node
		if ( syntax.size() > 0 ) {
			//json_push_back(syntaxn, json_new_a("test", "test"));
			// get signs node
			wstring output = syntax.substr(0, syntax.find_last_of(L"}"));
			JSONNode n(JSON_NODE);
			if(doc.GetTermBlocks().size() > 0) {
				//JSONNode blocks(JSON_ARRAY);	
				JSONNode blocks(JSON_ARRAY);
				blocks.set_name( L"signs blocks");
				for(std::list<XpmTermBlock*>::iterator it = doc.GetTermBlocks().begin(); it != doc.GetTermBlocks().end(); ++it) {
					JSONNode block(JSON_NODE);
					block.push_back(JSONNode(L"bp", (*it)->position()));
					JSONNode terms(JSON_ARRAY);
					terms.set_name( L"signs");
					block.push_back(terms);
					for(TermIter tit = (*it)->GetTerms().begin(); tit != (*it)->GetTerms().end(); ++tit) {
						cout << "write terms (1)" << endl;
						JSONNode term(JSON_NODE);						
						term.push_back(JSONNode(L"pos", json_int_t(tit->posInBlock())));
						term.push_back(JSONNode(L"signifier", tit->text().c_str()));
						term.push_back(JSONNode(L"signified", tit->iid().c_str()));
						terms.push_back( term);
					}
					blocks.push_back( block);
				}
				n.push_back( blocks);
				wstring signsstr = n.write_formatted().c_str();
				output += L"," + signsstr + L"}";
				//json_push_back(syntaxn, blocks);
			}
			//write file
			wcout << output << endl;
			ofstream outfile;
			outfile.open(m_filename.c_str());
			if ( outfile.is_open()) {
				outfile << output.c_str();
				outfile.close();
				return true;
			}
		}
		return false;
		//JSONNode syntaxn = libjson::
	}

	bool SignJson::SaveAsPureJson(XpmTermDoc& doc, const char* filename, wstring& syntax) {
		// get syntax node
		JSONNode syntaxn = libjson::parse(syntax.c_str());
		if ( !syntaxn.empty() ) {
			//json_push_back(syntaxn, json_new_a("test", "test"));
			// get signs node
			if(doc.GetTermBlocks().size() > 0) {
				//JSONNode blocks(JSON_ARRAY);	
				JSONNode blocks(JSON_ARRAY);
				blocks.set_name( L"signs blocks");
				for(std::list<XpmTermBlock*>::iterator it = doc.GetTermBlocks().begin(); it != doc.GetTermBlocks().end(); ++it) {
					cout << "write blocks" << endl;
					JSONNode block(JSON_NODE);
					block.push_back(JSONNode(L"bp", (*it)->position()));
					JSONNode terms(JSON_ARRAY);
					terms.set_name( L"signs");
					block.push_back( terms);
					for(TermIter tit = (*it)->GetTerms().begin(); tit != (*it)->GetTerms().end(); ++tit) {
						cout << "write terms (1)" << endl;
						JSONNode term(JSON_NODE);						
						term.push_back(JSONNode(L"pos", json_int_t(tit->posInBlock())));
						term.push_back(JSONNode(L"signifier", tit->text().c_str()));
						term.push_back(JSONNode(L"signified", tit->iid().c_str()));
						terms.push_back( term);
						cout << "write terms (2)" << endl;
					}
					blocks.push_back( block);
					cout << "write blocks (2)" << endl;
				}
				syntaxn.push_back( blocks);
				cout << "write blocks (3)" << endl;
			}
			//write file
			wstring output = syntaxn.write_formatted().c_str();
			wcout << output << endl;
			ofstream outfile;
			outfile.open(m_filename.c_str());
			if ( outfile.is_open()) {
				outfile << output.c_str();
				outfile.close();
				return true;
			}
		}
		return false;
		//JSONNode syntaxn = libjson::
	}

	int SignJson::Load(XpmTermDoc& doc, wstring str) {
		wcout << L"data:" << str << endl;
		JSONNode n = libjson::parse(str.c_str());
		if ( !n.empty() ) {
			JSONNode::json_iterator i =  n.begin();
			while ( i != n.end()) {
				wstring node_name = (*i).name().c_str();
				wcout << "node name:" << node_name << endl;
				if(json_strcmp((*i).name().c_str(), L"signs blocks")==0) {
					cout << "parse with json (1)" << endl;
					// parse signs blocks
					ParseSignsBlocks(*i, doc);
					i = n.erase(i);
					cout << "parse with json (2)" << endl;
				}else
					++i;

			}
			return true;
		}
		return true;
	}

	wstring SignJson::ParseWithJson(const char* filename, XpmTermDoc& doc) {
		ifstream infile;
		infile.open(m_filename.c_str());
		if(infile.is_open()) {
			wstring str((std::istreambuf_iterator<char>(infile)), istreambuf_iterator<char>());
			wcout << "data:" << str << endl;
			JSONNode n = libjson::parse(str.c_str());
			if ( !n.empty()  ) {
				JSONNode::json_iterator i = n.begin();
				while ( i != n.end()) {
					wstring node_name = (*i).name().c_str();
					wcout << "node name:" << node_name << endl;
					if(json_strcmp((*i).name().c_str(), L"signs blocks")==0) {
						cout << "parse with json (1)" << endl;
						// parse signs blocks
						ParseSignsBlocks(*i, doc);
						i = n.erase(i);
						cout << "parse with json (2)" << endl;
					}else
						++i;

				}
				return n.write_formatted().c_str();
			}
		}
		
		return L"";
	}

	void SignJson::ParseSignsBlocks(JSONNode n, XpmTermDoc& doc) {
		JSONNode::json_iterator i = n.begin();
		cout << "parse with block (1)" << endl;
		while ( i != n.end()) {			
			XpmTermBlock* block = doc.CreateBlockAtEnd();
			JSONNode::json_iterator bi = (*i).begin();
			while ( bi != (*i).end()) {
				if(json_strcmp((*bi).name().c_str(), L"bp")== 0) {	
					int bp = (*bi).as_int();
					cout << "bp :" << bp << endl;
					block->setTextBlockPos(bp);
				}else if ( json_strcmp((*bi).name().c_str(), L"signs")==0 ) {
					ParseSigns(*bi, block);
				}
				++bi;
			}
			++i;
		}
		cout << "parse with block (2)" << endl;
	}
	
	void SignJson::ParseSigns(JSONNode n, XpmTermBlock* block) {
		JSONNode::json_iterator i =  n.begin();
		cout << "parse with signs (1)" << endl;
		while ( i != n.end()) {			
			JSONNode::json_iterator ti= (*i).begin();
			int pos = 0;
			string iid = "";
			wstring signifier = L"";
			while ( ti != (*i).end()) {
				wstring node_name = (*ti).name().c_str();
				if( node_name == L"pos") {				
					pos = (*ti).as_int();
				}else if ( node_name == L"signifier" ) {
					signifier = libjson::to_std_wstring( (*ti).as_string());
				}else if ( node_name == L"signified" ) {
					iid = libjson::to_std_string( (*ti).as_string());
				}
				++ti;
			}
			block->AppendTermRange(pos, signifier, _termControl->GetTermByIid( iid));
			++i;
		}
		cout << "parse with signs (2)" << endl;
	}
}